﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpCancelJoinCmd.h"
#include "CmdStatusUtils.h"
#include "GbmpUiPlatformCommandIds.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "IDocument.h"
#include "ISelection.h"
#include "IGraphicsNodeReference.h"
#include "NotificationUtils.h"
#include "IElementJoin.h"
#include "IUserTransaction.h"
#include "IJoinRelationshipBehavior.h"
#include "IGeometryRelationshipComponent.h"
#include "UiDocumentViewUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

REGISTER_GM_COMMAND(GbmpCancelJoinCmd);

GbmpCancelJoinCmd::GbmpCancelJoinCmd() : GbmpCommandBase(ID_CMD_GBMP_CANCEL_STRUCTURE_JOIN)
{
}

GbmpCancelJoinCmd::~GbmpCancelJoinCmd()
{
}

bool GbmpCancelJoinCmd::IsEnabled() const
{
    CMD_ONLY_ENABLE_IN_PROJECT_ENVIRONMENT
}
bool GbmpCancelJoinCmd::IsVisible() const
{
    CMD_ONLY_VISIBLE_IN_PROJECT_ENVIRONMENT
}

gcmp::OwnerPtr<IAction> GbmpCancelJoinCmd::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    const GraphicsNodeReferenceOwnerPtrSet& selectedElems = gcmp::ISelection::Get()->GetGraphicsNodeReferences();

    std::set<ElementId> selectedModelIds;    
    FOR_EACH(elem, selectedElems)
    {
        if (elem->IsGraphicsElementShapeReference())
        {
            selectedModelIds.emplace(elem->GetElementId());
        }
    }

    std::set<ElementId> elementJoinId;
    CalculateElementJoinRelationshipInContainer(selectedModelIds, elementJoinId);

    OwnerPtr<IUserTransaction> pUserTransaction = IUserTransaction::Create(UiDocumentViewUtils::GetCurrentDocument(), GBMP_TR(L"删除连接"));
    DBG_WARN_AND_RETURN_UNLESS(pUserTransaction != nullptr, nullptr, L"事务创建不成功",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    FOR_EACH(joinId, elementJoinId)
    {
        pDoc->DeleteElement(joinId);
    }
    std::wstring notificationStr = L"共有" + StringUtil::ToWString(elementJoinId.size()) + L"个连接断开！";

    NotificationUtils::PostNotification(NotificationTypes::WarningNotificationType, notificationStr);
    pUserTransaction->Commit();
    
    return nullptr;
}

void gcmp::GbmpCancelJoinCmd::CalculateElementJoinRelationshipInContainer(const std::set<ElementId>& selectedModelIds, std::set<ElementId>& elementJoinId)
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pCurve为空",L"GDMPLab",L"2024-03-30");
    for (auto elementId : selectedModelIds)
    {
        const IElement* pElement = pDoc->GetElement(elementId);
        if (pElement == nullptr)
            continue;

        const IGeometryRelationshipComponent* pGeometryRepCpt = pElement->GetGeometryRelationshipComponent();
        if (!pGeometryRepCpt || !pGeometryRepCpt->GetJoinRelationship())
            continue;

        const IJoinRelationshipBehavior* pJoinRelationshipBehavior = pGeometryRepCpt->GetJoinRelationship();
        if (!pJoinRelationshipBehavior)
            continue;

        std::set<ElementId> joinIds;
        joinIds.insert(pJoinRelationshipBehavior->GetElementJoinIdsAtStart().begin(), pJoinRelationshipBehavior->GetElementJoinIdsAtStart().end());
        joinIds.insert(pJoinRelationshipBehavior->GetElementJoinIdsAtEnd().begin(), pJoinRelationshipBehavior->GetElementJoinIdsAtEnd().end());
        joinIds.insert(pJoinRelationshipBehavior->GetElementJoinIdsAtMiddle().begin(), pJoinRelationshipBehavior->GetElementJoinIdsAtMiddle().end());

        FOR_EACH(joinId, joinIds)
        {
            if (joinId.IsValid() && IsAttachedOrAttachingIdInContainer(joinId, selectedModelIds, elementId))
                elementJoinId.emplace(joinId);
        }
    }
}

bool gcmp::GbmpCancelJoinCmd::IsAttachedOrAttachingIdInContainer(const ElementId& elementJoinId, const std::set<ElementId>& selectedModelIds, const ElementId& elementId)
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pCurve为空",L"GDMPLab",L"2024-03-30");

    IElementJoin* pElementJoin = quick_cast<IElementJoin>(pDoc->GetElement(elementJoinId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");
    ElementId attachedId = pElementJoin->GetAttachedId();
    ElementId attachingId = pElementJoin->GetAttachingId();
    if (elementId != attachingId && elementId != attachedId)
    {
        DBG_WARN(L"传入参数有误",L"GDMPLab",L"2024-03-30");
        return false;
    }
    ElementId id = elementId == attachedId ? attachingId : attachedId;
    if (ValueContainerUtil::IsInContainer(selectedModelIds, id))
    {
        return true;
    }
    return false;
}
